package mac.eventRecognizer.pedlParser;

import mac.types.parserTypes.*;
import mac.eventRecognizer.interpreter.*;

public class ASTExpression extends SimpleNode {
  static final int VARIABLE = 0;
  static final int CAST = 1;
  static final int METHOD = 2;
  static final int ADD = 3;
  static final int SUBTRACT = 4;
  static final int MULTIPLY = 5;
  static final int DIVIDE = 6;
  static final int MOD = 7;
  static final int PLUS = 8;	// unary operator
  static final int MINUS = 9;	// unary operator
  static final int TIME = 10;
  static final int VALUE = 11;
  static final int PARENTHESIS = 12;
  static final int CONSTANT = 13;
  static final int LSHIFT = 14;
  static final int RSHIFT = 15;
  static final int ARRAY = 16;
  static final int TYPE = 17;

  protected int type;
  protected String name;
  protected Object oldValue;

  ASTExpression(int id) {
    super(id);
  }

  public int getType() {
    return type;
  }
  public String getName() {
    return name;
  }



  public Object getOldValue() {
    return oldValue;
  }

  public void setType(int t) {
    type = t;
  }
  public void setName(String n) {
    name = n;
  }
  public Object evaluate() {
      Object tempValue = null;
      Object tempOldValue = null;
      Object newValue = null;	// a result of evaluation
      SymtabEntry se = null;	// an entry of symbol table which is used for 
				// a condition id or a program variable
      if( mark) {		// If this node is already evaluated, 
      //System.err.println(this); 
      return value;
      }
				// it just returns value.
      mark = true;

      if(type != VARIABLE ) {	// The only possibility of re-evaluating
				//( thus, copying new value into old value ) 
				//exists when ASTCondition of type VARIABLE 
				//is evaluated
	  oldValue = value;
      }  else {
	  // NOT YET COMPLETELY VERIFIED
	  se = (SymtabEntry)value;
	  if( se.getType().equals("_macType")) { // Condition id
	      tempValue = ((Node)(se.getValue())).getValue();
	      tempOldValue = ((ASTCondition)(se.getValue())).getOldValue();
	      if(se.isUpdated()) {
		  oldValue = tempOldValue;
	      } else {
		  oldValue = tempValue;
	      }
	  } else {	// Boolean Variable
	      oldValue =  se.getOldValue();
	  }

	  if(se.isUpdated())  {	// It's the first time evaluation of 
					// condition or
					// it's not changed at all.
					// Copy value into oldValue
	      oldValue = tempOldValue;
	  } else {	// ASTCondition of type VARIABLE is already updated
			// Just copy its value and old value here
	      oldValue =  tempValue;
	  }


      }


      switch(type) {
	  /* This node is either a program variable or a condition id.  It 
	   * does not have a child.  Its value
	   * is a pointer to an entry in a symbol table whose key is id of
	   * this node.  Be careful NOT to update value */
	  case VARIABLE :
	  {
	      se = (SymtabEntry)value;
	      if( se.getType().equals("_macType")) { // condition id   
		  newValue = ((ASTCondition)(se.getValue())).evaluate();
		  //System.err.println("VARIABLE's value is connected to type " +
		//	  ((ASTCondition)(se.getValue())).op );
	      }
	      else {	// program variable
		  newValue = se.getValue();
	      }
	      //System.err.println(name + ", isUpdated = " + se.isUpdated());
	      //System.err.println(EventRecognizer.symbolTbl);
	      //System.err.println(se);

	      break;
	  }
	  /**
	   *  WE HAVE TO CHANGE ALL FOLLOWING SECTION FOR GENERAL CASES
	   *  it only covers two childres, sorry
	   */
	  case ADD :
	  case SUBTRACT:
	  case MULTIPLY:
	  case DIVIDE:
	  case MOD:
	  case LSHIFT:
	  case RSHIFT:
	  {
	      Object leftValue = jjtGetChild(0).evaluate(); 
	      Object rightValue = jjtGetChild(1).evaluate(); 
	      boolean result;

	      value = ASTExpressionAux.evalValue(leftValue,rightValue,type);
	      break;
	  }

	  case PARENTHESIS:
	      value = jjtGetChild(0).evaluate(); 
	      break;

	  case CONSTANT: break;

	  case TIME:
	  case VALUE:
	  case ARRAY:
	  case CAST:
	  case TYPE:

	  case PLUS:
	  case MINUS:
	      System.err.println("TIME,VALUE,ARRAY,CAST,TYPE,PLUS,MINUS and CONSTANT" +
		      " are not yet implemented");
	  default: 
	      System.err.println("No proper type " + type + " at " + this); 
	      break;
      }
      if(type != VARIABLE) {	
	  newValue = value;
      }
  //    System.err.println("--------------");	    
   //   System.err.println(this);
  //    System.err.println(this); 
      return newValue;
  }


  public String toString() {
    String s= null;
    String s2= null;
    Object realValue = null;
    SymtabEntry se = null;
    Object defNode = null;

    switch (type) {
      case VARIABLE: s =  "Expression: variable "+name;break;
      case CAST: s =  "Expression: type cast";break;
      case METHOD: s =  "Expression: method";break;
      case ADD: s =  "Expression: addition";break;
      case SUBTRACT: s =  "Expression: subtraction";break;
      case MULTIPLY: s =  "Expression: multiplication";break;
      case DIVIDE: s =  "Expression: division";break;
      case MOD: s =  "Expression: mod";break;
      case PLUS: s =  "Expression: plus";break;
      case MINUS: s =  "Expression: minus";break;
      case TIME: s =  "Expression: time";break;
      case VALUE: s =  "Expression: value";break;
      case PARENTHESIS: s =  "Expression: parenthesis";break;
      case CONSTANT: s =  "Expression: constant";break;
      case LSHIFT: s =  "Expression: left shift";break;
      case RSHIFT: s =  "Expression: right shift";break;
      case ARRAY: s =  "Expression: array";break;
      case TYPE: s =  "Expression: type";break;
      default: s =  "Expression: error";break;
    }
      if(value instanceof SymtabEntry) {
	  se = (SymtabEntry)value;
	  if( ((String)(se.getType())).equals("_macType")) {
	      realValue = ((Node)(se.getValue())).getValue(); 
	      //System.err.println("name :" + name + "value :" + realValue);
	      defNode = se.getValue();
	  } else {
	      realValue = se.getValue();
	  }
      } else {
	  realValue = value;
      }

      return s + "(name:"+ name + ",value:" 
	    + realValue + ",mark:" + mark + ",address:"  + ")"  
	    + "pointing to " + defNode;

  }
  public boolean isUpdated() { 
      if(type != VARIABLE) {
	  System.err.println("isUpdated must not be called at " + this);
	  return  false;
      } else {
	  return ((SymtabEntry)getValue()).isUpdated();
      }
  }
      
}
